﻿using KAs.Application.Contract.Dto;
using KAs.Application.Contract.Svc;
using KAs.Common.Exceptions;
using KAs.SqlSugar;
using KAs.Utils.Http;
using Microsoft.Extensions;
using Microsoft.Extensions.Caching.Distributed;
using Microsoft.Extensions.Configuration;
using RN.User.Application.Contract.Dto;
using RN.User.Application.Contract.Svc;
using RN.User.Domain;

namespace RN.User.Application;

// 无curd服务示例
public class UserAppService : IUserAppService
{
    private readonly IDistributedCache _cache;
    private readonly IRepository<UserInfo, long> _repository;
    private readonly ICurrentUserInfo _userInfo;
    private readonly IConfiguration _configuration;

    public UserAppService(IDistributedCache cache,
        IRepository<UserInfo, long> repository,
        ICurrentUserInfo userInfo,
        IConfiguration configuration)
    {
        _cache = cache;
        _repository = repository;
        _userInfo = userInfo;
        _configuration = configuration;
    }

    public async Task<LoginReturnDto> LoginAsync(LoginDto dto)
    {
        var userInfo = await _repository.GetFirstAsync(x => x.Account == dto.Account);
        if (userInfo == null || userInfo.Password != dto.Password.PwdEncryption(dto.Account))
            throw new Exception("账户名不存在或密码错误");
        if (!userInfo.IsAdmin)
            throw new Exception("非合法账户");
        var token = Guid.NewGuid().ToString("N");
        var userInfoDto = new UserInfoDto()
        {
            Uid = userInfo.Id.ToString(),
            Name = userInfo.UserName,
            IsAdmin = true
        };
        await _cache.CacheAsync($"token:{token}", userInfoDto, 3600);
        var result = new LoginReturnDto()
        {
            Token = token,
            User = userInfo.SimpleMapTo<UserDto>()
        };
        return result;
    }

    public async Task<LoginReturnDto> WeixinLoginAsync(WeixinLoginDto dto)
    {
        if (dto.OpenId.IsNullOrEmpty())
            throw new BusinessException("openid is null.");

        var userInfo = await _repository.GetFirstAsync(x => x.OpenId == dto.OpenId);
        if (userInfo == null)
            throw new BusinessException("openid is unvaild.");

        var userInfoDto = new UserInfoDto()
        {
            Uid = userInfo.Id.ToString(),
            Name = userInfo.UserName,
            OpenId = userInfo.OpenId,
            IsAdmin = true
        };
        var token = await _cache.SetTokenAsync(userInfoDto);
        var result = new LoginReturnDto()
        {
            Token = token,
            User = userInfo.SimpleMapTo<UserDto>()
        };
        return result;
    }

    public async Task<LoginReturnDto> WeixinGrantAsync(WeixinGrantDto dto)
    {
        var dicParams = new Dictionary<string, string>()
        {
            { "appid", _configuration["WeixinMP:AppId"] },
            { "secret", _configuration["WeixinMP:Secret"] },
            { "js_code", dto.Code },
            { "grant_type", "authorization_code" },
        };
        var responseDto = await HttpHelp.GetAsync<WeixinAuthorResponseDto>("https://api.weixin.qq.com/sns/jscode2session", dicParams);
        if (responseDto == null || responseDto.ErrCode != WeixinAuthorErrCodeEnum.Success)
            throw new BusinessException("-1", "微信登录异常");

        var userInfo = await _repository.GetFirstAsync(x => x.OpenId == responseDto.OpenId);
        userInfo ??= await CreateNewUser(responseDto.OpenId);

        var userInfoDto = new UserInfoDto()
        {
            Uid = userInfo.Id.ToString(),
            Name = userInfo.UserName,
            OpenId = userInfo.OpenId,
            IsAdmin = true
        };
        var result = new LoginReturnDto()
        {
            Token = await _cache.SetTokenAsync(userInfoDto),
            User = userInfo.SimpleMapTo<UserDto>()
        };
        return result;
    }

    private async Task<UserInfo> CreateNewUser(string openId)
    {
        var newUser = new UserInfo
        {
            OpenId = openId,
            Account = openId.Md5Encryption()[..8],
            UserName = openId.Md5Encryption()[..8],
            Password = openId.Md5Encryption()[..8].PwdEncryption(openId.Md5Encryption()[..8]),
            Gender = Domain.Share.GenderEnum.Secrecy
        };
        return await _repository.InsertReturnEntityAsync(newUser);
    }

    public async Task<UserInfoDto> GetUserInfoAsync()
    {
        return _userInfo.GetUserInfo();
    }
}
